package com.xd.core.system.service.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xd.common.constant.SysConstant;
import com.xd.common.exception.Assert;
import com.xd.common.exception.XkdException;
import com.xd.common.http.ResponseResult;
import com.xd.common.util.SecurityUtil;
import com.xd.core.system.entity.SysPermission;
import com.xd.core.system.entity.SysRolePermission;
import com.xd.core.system.mapper.SysPermissionMapper;
import com.xd.core.system.mapper.SysRolePermissionMapper;
import com.xd.core.system.service.ISysPermissionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单表 服务实现类
 * </p>
 *
 * @author SJ
 * @since 2023-03-15
 */
@Slf4j
@Service
public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, SysPermission> implements ISysPermissionService {

    @Autowired
    private SysPermissionMapper sysPermissionMapper;
    @Autowired
    private SysRolePermissionMapper sysRolePermissionMapper;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    @Override
    public List<SysPermission> getAddList() {
        Integer roleId = SecurityUtil.getLoginUser().getRole().getId();
        List<SysPermission> sysPermissions = sysPermissionMapper.selectPersByRole(roleId);
        return getPermissionTreeByList(sysPermissions);
    }

    @Override
    public List<SysPermission> getUpdateList(Integer roleId) {
        Integer id = SecurityUtil.getLoginUser().getRole().getId();
        List<SysPermission> list = sysPermissionMapper.selectPersByRole(id);
        List<Integer> ids = sysRolePermissionMapper.selectPerIds(roleId);
        list = list.stream().filter(a -> {
            ids.forEach(b -> {
                if (a.getId().equals(b)) {
                    a.setPerStatus(true);
                }
            });
            return true;
        }).collect(Collectors.toList());
        return getPermissionTreeByList(list);
    }


    @Override
    public List<SysPermission> userPers(Integer roleId) {
        List<SysPermission> list = sysPermissionMapper.selectPersByRole(roleId);
        return getPermissionTreeByList(list);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addPer(SysPermission entity) {
        if (null == entity.getPerms())
            throw new XkdException("权限标识不能为空");
        Assert.yes(sysPermissionMapper.selectCount(new LambdaQueryWrapper<SysPermission>().eq(SysPermission::getPerms, entity.getPerms())), "权限标识不能重复");
        sysPermissionMapper.insert(entity);
        //默认给平台超管所有权限
        SysRolePermission sysRolePermission = new SysRolePermission();
        sysRolePermission.setPermissionId(entity.getId());
        sysRolePermission.setRoleId(SysConstant.SYS_ROLE_SUPER);
        sysRolePermission.setCompanyId(SysConstant.SUPER_COMPANY_ID);
        sysRolePermissionMapper.insert(sysRolePermission);
    }

    @Override
    public void updatePer(SysPermission entity) {
        if (null == entity.getId()) throw new XkdException("权限ID为必传项");
        SysPermission crmSysPermission = sysPermissionMapper.selectById(entity.getId());
        if (null == entity.getPerms())
            throw new XkdException("权限标识不能为空");
        if (!crmSysPermission.getPerms().equals(entity.getPerms()))
            Assert.yes(sysPermissionMapper.selectCount(new LambdaQueryWrapper<SysPermission>().eq(SysPermission::getPerms, entity.getPerms())), "权限标识不能重复");
        sysPermissionMapper.updateById(entity);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deletePer(Integer id) {
        //删除角色权限关联
        LambdaQueryWrapper<SysRolePermission> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysRolePermission::getPermissionId, id);
        sysRolePermissionMapper.delete(wrapper);
        //删除自己
        sysPermissionMapper.deleteById(id);

        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {//事务成功后执行
                try {
                    String pattern = "permission:*";
                    redisTemplate.execute((RedisCallback<Void>) connection -> {
                        try (Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(pattern).build())) {
                            cursor.forEachRemaining(connection::del);
                        }
                        return null;
                    });
                    log.info("删除用户权限缓存");
                    // 延迟再删一次，防止并发脏写
                    CompletableFuture.runAsync(() -> {
                        try {
                            Thread.sleep(500); // 500ms
                            redisTemplate.execute((RedisCallback<Void>) connection -> {
                                try (Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(pattern).build())) {
                                    cursor.forEachRemaining(connection::del);
                                }
                                return null;
                            });
                            log.info("Keys matching pattern {} have been deleted", pattern);
                            log.info("第二次删除用户权限缓存");
                        } catch (InterruptedException e) {
                            log.error("延迟删除缓存失败", e);
                        }
                    });
                } catch (Exception e) {
                    throw new XkdException("删除权限缓存错误");
                }
            }
        });
    }

    @Override
    public List<SysPermission> getOpenList() {
        return getPermissionTree(null);
    }


    //查询树中所有ID 返回integers
    public void getTreeIds(List<SysPermission> allList, List<Integer> integers) {
        List<Integer> collect = allList.stream().map(SysPermission::getId).collect(Collectors.toList());
        integers.addAll(collect);
        for (SysPermission sysPermission : allList) {
            if (CollectionUtils.isNotEmpty(sysPermission.getChildren())) {
                getTreeIds(sysPermission.getChildren(), integers);
            }
            return;
        }
    }


    //查询权限树
    private List<SysPermission> getPermissionTree(List<Integer> ids) {
        List<SysPermission> perTree = new ArrayList<>();
        HashMap<Integer, SysPermission> map = new HashMap<>();
        List<SysPermission> sysPermissions = sysPermissionMapper.getOpenList(ids);
        sysPermissions.forEach(
                p -> {
                    map.put(p.getId(), p);
                    SysPermission parent = map.get(p.getParentId());
                    if (parent != null) {
                        parent.addChild(p);
                    } else {
                        perTree.add(p);
                    }
                }
        );
        return perTree;
    }

    //查询权限树
    @Override
    public List<SysPermission> getPermissionTreeByList(List<SysPermission> sysPermissions) {

        List<SysPermission> perTree = new ArrayList<>();
        HashMap<Integer, SysPermission> map = new HashMap<>();
        sysPermissions.forEach(
                p -> {
                    map.put(p.getId(), p);
                    SysPermission parent = map.get(p.getParentId());
                    if (parent != null) {
                        parent.addChild(p);
                    } else {
                        perTree.add(p);
                    }
                }
        );
        return perTree;
    }

    @Override
    public List<String> getPersByRoleId(Integer id) {
        return sysPermissionMapper.getPersByRoleId(id);
    }

}
